
#include "Renderer.h"
#include "Synaptic/Surface.h"
#include "Resource/Graphic.h"

namespace Engine {

Misc::Frame Renderer::camera; // Camera position and viewing frame
Renderer::RenderTypes Renderer::renderType = RENDERER_NOT_DEFINED; 
Misc::Frame Renderer::windowFrame; 
SDL_Surface * Renderer::screen = 0; 
bool Renderer::raise(Renderer::RenderTypes type, int width, int height) throw(char *)
{
	int flags = 0;
  	if (renderType != RENDERER_NOT_DEFINED)
		throw("Renderer already defined!");
	renderType = type;
	switch (type) {
		case (RENDERER_SOFTWARE):
			flags |= SDL_SWSURFACE;
			break;
		/* case (RENDERER_HARDWARE):
		 	initalize opengl enviroenment
			make necessary changes to tell the
			engine to use opengl. such winky winky.
			some day i'll learn, promise.
		 	flags |= SDL_OPENGL;
			break;
		*/
		default:
			renderType = RENDERER_NOT_DEFINED;
			throw("Renderer not defined!");
			break;
	}
	flags |= SDL_DOUBLEBUF;
	windowFrame.x = 0;
	windowFrame.y = 0;
	windowFrame.w = width;
	windowFrame.h = height;
	if ((screen = SDL_SetVideoMode(width, height, 32, flags)) == NULL)
		throw(SDL_GetError());
	
	camera = windowFrame;

	// screen is OK and should be appearing by now.
	return true;
}

// Render graphics into screen using default renderer
void Renderer::render(const Engine::Resource::Graphic & visual)
{
	Misc::Frame destFrame(visual.position.x + visual.xScreenOffset,
						  visual.position.y + visual.yScreenOffset,
						  0,
						  0),
				srcFrame(visual.frame.x + visual.xFrameOffset,
						 visual.frame.y + visual.yFrameOffset,
						 visual.frame.w,
						 visual.frame.h);
						  
	/* rotate the surface if needed. This should be done in 'graphic' class? */
	SDL_Surface * surface = visual.surface;
	if (visual.rotation != 0.0f) {
		// rotate the surface
		char surfName[510];
		std::sprintf(surfName,"%s:r=%.1f", visual.surfaceName.c_str(), visual.rotation);
		surface = Synaptic::Surface::rotate(visual.surfaceName, visual.rotation, surfName);
		destFrame.x = ((visual.surface->w/2 - surface->w/2)) + visual.position.x + visual.xScreenOffset;
		destFrame.y = ((visual.surface->h/2 - surface->h/2)) + visual.position.y + visual.yScreenOffset;
		srcFrame.w = surface->w;
		srcFrame.h = surface->h;
	}
	
	/* apply camera translation */
	destFrame.x -= camera.x;
	destFrame.y -= camera.y;
	
	Synaptic::Surface::blit(surface, srcFrame, screen, destFrame);
}

// Render graphics into another graphic using default renderer
void Renderer::render(const Engine::Resource::Graphic & sourceVisual, Engine::Resource::Graphic & destinationVisual){
	Misc::Frame destFrame(sourceVisual.position.x + sourceVisual.xScreenOffset,
						  sourceVisual.position.y + sourceVisual.yScreenOffset,
						  0,
						  0),
				srcFrame(sourceVisual.frame.x + sourceVisual.xFrameOffset,
						 sourceVisual.frame.y + sourceVisual.yFrameOffset,
						 sourceVisual.frame.w,
						 sourceVisual.frame.h);
						  
	/* rotate the surface if needed. This should be done in 'graphic' class? */
	SDL_Surface * sourceSurface = sourceVisual.surface;
	SDL_Surface * destinationSurface = destinationVisual.surface;
	
	if (sourceVisual.rotation != 0.0f) {
		// rotate the surface
		char surfName[510];
		std::sprintf(surfName,"%s:r=%.1f", sourceVisual.surfaceName.c_str(), sourceVisual.rotation);
		sourceSurface = Synaptic::Surface::rotate(sourceVisual.surfaceName, sourceVisual.rotation, surfName);
		destFrame.x = ((sourceVisual.surface->w/2 - sourceSurface->w/2)) + sourceVisual.position.x + sourceVisual.xScreenOffset;
		destFrame.y = ((sourceVisual.surface->h/2 - sourceSurface->h/2)) + sourceVisual.position.y + sourceVisual.yScreenOffset;
		srcFrame.w = sourceSurface->w;
		srcFrame.h = sourceSurface->h;
	}
	Synaptic::Surface::blit(sourceSurface, srcFrame, destinationSurface, destFrame);	
}

void Renderer::flip()
{
	SDL_Flip(screen);
}

Renderer::Renderer() {
}

Renderer::~Renderer() {
}


} // namespace Engine
